﻿using AutoMapper;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using RQX.Common.Web.Tools;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace RQX.Common.Web.Core.AutoMapper
{
    public static class AutoMapperExtension
    {
        private static IMapper _mapper;
        public static void AddAutoMapper(this IServiceCollection services)
        {
            services.AddAutoMapper(cfg =>
            {
                cfg.AddProfile<AutoMapperProfile>();
            }, Assembly.GetExecutingAssembly());
        }

        public static void UseStateAutoMapper(this IApplicationBuilder applicationBuilder)
        {
            _mapper = applicationBuilder.ApplicationServices.GetRequiredService<IMapper>();
        }

        //public static TDestination Map<TDestination>(object source)
        //{
        //    var mapper = ServiceProvider.GetRequiredService<IMapper>();

        //    return mapper.Map<TDestination>(source);
        //}

        //public static TDestination Map<TSource, TDestination>(TSource source)
        //{
        //    var mapper = ServiceProvider.GetRequiredService<IMapper>();

        //    return mapper.Map<TSource, TDestination>(source);
        //}

        //public static TDestination MapTo<TSource, TDestination>(this TSource source)
        //{
        //    var mapper = ServiceProvider.GetRequiredService<IMapper>();

        //    return mapper.Map<TSource, TDestination>(source);
        //}
        /// <summary>
        /// 处理跨插件调用，automapper自动映射
        /// </summary>
        /// <typeparam name="TDestination"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        private static TDestination TransferSingle<TDestination>(object source)
        {
            var sourceType = source.GetType();
            var targetType = typeof(TDestination);
            var sourceCurrentType = AutoMapperCurrentType.GetType(sourceType.FullName);
            var destinationCurrentType = AutoMapperCurrentType.GetType(targetType.FullName);

            var sourceObj = CreateInstance(sourceCurrentType);
            source.PlugCopyTo(sourceObj);
            var destinationObj = _mapper.Map(sourceObj, sourceCurrentType, destinationCurrentType);
            var resultObj = CreateInstance(targetType);
            destinationObj.PlugCopyTo(resultObj);
            return (TDestination)resultObj;
        }
        /// <summary>
        /// 构造实体
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private static object CreateInstance(Type type)
        {
            return type.Assembly.CreateInstance(type.FullName);
        }
        /// <summary>
        /// 单类映射
        /// </summary>
        /// <typeparam name="TDestination"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        public static TDestination MapTo<TDestination>(this object source)
        {
            var sourceType = source.GetType();
            var sourceCurrentType = AutoMapperCurrentType.GetType(sourceType.FullName);
            if (sourceCurrentType == sourceType)
            {
                return _mapper.Map<TDestination>(source);
            }
            else
            {
                return TransferSingle<TDestination>(source);
            }
        }
        /// <summary>
        /// 列表映射，跨插件调用需要使用该方法
        /// </summary>
        /// <typeparam name="TDestination"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        public static IEnumerable<TDestination> MapToList<TDestination>(this IEnumerable<object> source)
        {
            var sourceType = source.AsQueryable().ElementType;
            var sourceCurrentType = AutoMapperCurrentType.GetType(sourceType.FullName);
            if (sourceType == sourceCurrentType)
            {
                return _mapper.Map<IEnumerable<TDestination>>(source);
            }
            else
            {
                List<TDestination> resultList = new List<TDestination>();
                source.ForEach(item =>
                {
                    resultList.Add(TransferSingle<TDestination>(item));
                });
                return resultList;
            }
        }
    }
}
